#pragma once
#include <functional>
#include "Socket.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace socket_ns;

static const int gport = 8888;

using service_t = std::function<std::string (std::string &requeststr)>;

// 面向字节流
class TcpServer
{
public:
    TcpServer(service_t service,uint16_t port = gport)
        :_port(port),
        _listensock(std::make_shared<TcpSocket>()),
        _isrunning(false),
        _service(service)
    {
        _listensock->BuildListenSocket(_port);
    }

    // 内部类
    class ThreadData
    {
    public:
        SockSPtr _sockfd;
        TcpServer* _self;
        InetAddr _addr;
    public:
        ThreadData(SockSPtr sockfd,TcpServer* self,const InetAddr &addr)
            :_sockfd(sockfd),_self(self),_addr(addr)
        {}
    };
    void Loop()
    {
        _isrunning = true;
        while(_isrunning)
        {
            InetAddr client;
            SockSPtr newsock = _listensock->Accepter(&client); // 获取连接
            if(newsock == nullptr) 
                continue;
            LOG(INFO,"get a new link,client info: %s,sockfd:%d\n",client.AddrStr().c_str(),newsock->Sockfd()); 
            
            // 获取成功
            // version 2 -- 多线程版 -- 不能关闭fd了，也不需要 
            pthread_t tid;
            ThreadData *td = new ThreadData(newsock, this,client);
            pthread_create(&tid,nullptr,Execute,td); // 新线程分离
        }
        _isrunning = false;
    }
    // 无法调用类内成员 无法看到sockfd
    static void *Execute(void *args)
    {
        ThreadData *td = static_cast<ThreadData *>(args);
        pthread_detach(pthread_self()); // 分离新线程，无需主线程回收
        
        std::string requeststr;
        // 后面不做请求的分离，我们认为读到的是一个完整的请求 -bug
        ssize_t n = td->_sockfd->Recv(&requeststr);
        if(n > 0)
        {
            std::string responsestr = td->_self->_service(requeststr); // 执行回调
            td->_sockfd->Send(responsestr);
        }
        
        td->_sockfd->Close();
        delete td;
        return nullptr;
    }
    ~TcpServer()
    {}
private:
    uint16_t _port;
    SockSPtr _listensock;
    bool _isrunning;
    service_t _service; // // 执行方法
};
